//
// Created by ct on 2021/9/26.
//
#include "lib/common.h"

#define MAX_LINE 1024
#define FD_INIT_SIZE 128

//typedef ssize_t  bool;

char rot13_char(char c) {
    if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
        return (char) (c + 13);
    else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
        return (char) (c - 13);
    else
        return c;
}

//数据缓冲区
typedef struct DATA_BUFFER {
    int connect_fd; // 连接字ID
    char fact_buffer[MAX_LINE];//实际缓冲
    ssize_t read_index; //缓冲写入位置
    ssize_t write_index;//缓冲读取位置
    bool readable;//是否可以读
} buffer;

buffer *malloc_buffer() {
    buffer *bfr = malloc(sizeof(buffer));
    if (!bfr) return NULL;
    bfr->connect_fd = 0;
    bfr->write_index = bfr->read_index = bfr->readable = 0;
    return bfr;
}

void free_buffer(buffer *bfr) {
    free(bfr);
}


int on_socket_read(int fd, buffer *bfr) {
    char buf[1024];
    int i;
    ssize_t result;
    while (1) {
        result = recv(fd, buf, sizeof(buf), 0);
        if (result <= 0) break;
        for (i = 0; i < result; ++i) {
            if (bfr->write_index < sizeof(bfr->fact_buffer))
                bfr->fact_buffer[bfr->write_index++] = rot13_char(buf[i]);
            if (buf[i] == '\n') {
                bfr->readable = 1; //缓冲区可以读
            }
        }
    }
    if (result == 0) {
        return 1;
    } else if (result < 0) {
        if (errno == EAGAIN) return 0;
        return -1;
    }
    return 0;
}

int on_socket_write(int fd, buffer *bfr) {
    while (bfr->read_index < bfr->write_index) {
        ssize_t result = send(fd, bfr->fact_buffer + bfr->read_index, bfr->write_index - bfr->read_index, 0);
        if (result < 0) {
            if (errno == EAGAIN) return 0;
            return -1;
        }
        bfr->read_index += result;
    }

    if (bfr->read_index == bfr->write_index)
        bfr->read_index = bfr->write_index = 0;
    bfr->readable = 0;
    return 0;

}

int main(int argc, char *argv[]) {
    int listen_fd;
    int i, maxfd;
     socket * s0;
    buffer *buffers[FD_INIT_SIZE];

    for (i = 0; i < FD_INIT_SIZE; ++i) {
        buffers[i] = malloc_buffer();
    }

    listen_fd = tcp_nonblocking_server_listen(SERV_PORT);

    fd_set readset, writeset, exset;
    FD_ZERO(&readset);
    FD_ZERO(&writeset);
    FD_ZERO(&exset);

    for (int j = 0; j < 10; ++j) {
        maxfd = listen_fd;

        FD_ZERO(&readset);
        FD_ZERO(&writeset);
        FD_ZERO(&exset);
        // listener加入readset

        FD_SET(listen_fd, &readset);

        // 主要是为了更新MAXFD
        for (i = 0; i < FD_INIT_SIZE; ++i) {
            if (buffers[i]->connect_fd > 0) {
                // 保持MAXFD最大
                if (buffers[i]->connect_fd > maxfd)
                    maxfd = buffers[i]->connect_fd;
                FD_SET(buffers[i]->connect_fd, &readset);
                if (buffers[i]->readable) {
                    FD_SET(buffers[i]->connect_fd, &writeset);
                }
            }
        }
        // 切换为内核状态执行select
        if (select(maxfd + 1, &readset, &writeset, &exset, NULL) < 0) {
            error(1, errno, "select error");
        }

        if (FD_ISSET(listen_fd, &readset)) {
            printf("listening socket readable\n");
            sleep(5);
            struct sockaddr_storage ss;
            socklen_t slen = sizeof(ss);
            int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen);

            if (fd < 0) {
                error(1, errno, "accept failed");
            } else if (fd > FD_INIT_SIZE) {
                error(1, 0, "too many connections");
                close(fd);
            } else {
                // 设置为非阻塞I/O
                make_nonblocking(fd);
                if (buffers[fd]->connect_fd == 0) {
                    buffers[fd]->connect_fd = fd;
                } else {
                    error(1, 0, "too many connections");
                }
            }

        }

        for (i = 0; i < maxfd + 1; ++i) {
            int r = 0;
            if (i == listen_fd) continue;
            if (FD_ISSET(i, &readset)) {
                r = on_socket_read(i, buffers[i]);
            }
            if (r == 0 && FD_ISSET(i, &writeset)) {
                r = on_socket_write(i, buffers[i]);
            }
            if (r) {
                buffers[i]->connect_fd = 0;
                close(i);
            }
        }
    }
}